package com.yyaccp.hncc.es.service.impl;

import com.yyaccp.hncc.es.domain.EsDrug;
import com.yyaccp.hncc.es.repository.EsDrugRepository;
import com.yyaccp.hncc.es.service.IEsDrugService;
import com.yyaccp.hncc.es.util.EsImportTemplate;
import com.yyaccp.hncc.es.util.HighlightSearchResultMapper;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.stereotype.Service;

import java.util.List;

/**
 * @author 天天向上 （john.yi@qq.com）
 * @date 2020/8/26
 */
@Service
@AllArgsConstructor
@Slf4j
public class EsDrugServiceImpl implements IEsDrugService {
    /**
     * 通用的增删改查使用repository
     */
    private final EsDrugRepository esDrugRepository;
    /**
     * 自定义的查询使用elasticsearchRestTemplate
     * 新版本已经不推荐使用elasticsearchTemplate
     * 推荐使用elasticsearchRestTemplate
     */
    private final ElasticsearchRestTemplate elasticsearchRestTemplate;
    private final HighlightSearchResultMapper highlightSearchResultMapper;


    public static final String DRUG_CODE = "code";
    public static final String DRUG_NAME = "name";
    public static final String DRUG_MANUFACTURER = "manufacturer";
    public static final String DRUG_GENERIC_NAME = "genericName";
    public static final String DRUG_PRICE = "price";

    @Override
    public void saveAll(List<EsDrug> esDrugList) {
        if (esDrugList.size() > EsImportTemplate.BULK_SIZE) {
            this.bulkIndex(esDrugList);
        } else {
            esDrugRepository.saveAll(esDrugList);
        }
    }

    @Override
    public void bulkIndex(List<EsDrug> esDrugList) {
        if (!elasticsearchRestTemplate.indexExists(EsDrug.class)) {
            elasticsearchRestTemplate.createIndex(EsDrug.class);
        }
        new EsImportTemplate<EsDrug>().bulkIndex(elasticsearchRestTemplate, esDrugList, false);
    }

    @Override
    public void delete() {
        elasticsearchRestTemplate.deleteIndex(EsDrug.class);
    }

    @Override
    public Page<EsDrug> query(String keyword, Integer start, Integer size, boolean highlight) {
        /* 1.创建QueryBuilder(即设置查询条件)这儿创建的是组合查询(也叫多条件查询),后面会介绍更多的查询方法
         * 组合查询BoolQueryBuilder
         * must(QueryBuilders)   :AND
         * mustNot(QueryBuilders):NOT
         * should:               :OR
         * termQuery             :精确查询，不分词
         * queryStringQuery      :text分词查询
         */
        BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
        queryBuilder.should(QueryBuilders.queryStringQuery(keyword).field(DRUG_CODE))
                .should(QueryBuilders.queryStringQuery(keyword).field(DRUG_GENERIC_NAME))
                .should(QueryBuilders.queryStringQuery(keyword).field(DRUG_MANUFACTURER))
                .should(QueryBuilders.queryStringQuery(keyword).defaultField(DRUG_NAME));
        //设置分页(从第一页开始，一页显示10条)
        //注意开始是从0开始，有点类似sql中的方法limit 的查询
        Pageable pageable = PageRequest.of(start, size);
        //构建查询
        NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();
        nativeSearchQueryBuilder
                // 查询条件
                .withQuery(queryBuilder)
                // 分页
                .withPageable(pageable)
                // 排序
                .withSort(SortBuilders.fieldSort(DRUG_PRICE).order(SortOrder.ASC));
        if (highlight) {
            // 高亮字段
            nativeSearchQueryBuilder.withHighlightFields(new HighlightBuilder.Field(DRUG_NAME),
                    new HighlightBuilder.Field(DRUG_CODE),
                    new HighlightBuilder.Field(DRUG_MANUFACTURER),
                    new HighlightBuilder.Field(DRUG_GENERIC_NAME)
                            // 自定义高亮样式，上面两个字段使用默认的<em>标签
                            .preTags("<span style='color:red'>")
                            .postTags("</span>"));
        }
        NativeSearchQuery searchQuery = nativeSearchQueryBuilder.build();
        // 执行查询
        if (highlight) {
            return elasticsearchRestTemplate.queryForPage(searchQuery, EsDrug.class, highlightSearchResultMapper);
        } else {
            return elasticsearchRestTemplate.queryForPage(searchQuery, EsDrug.class);
        }
    }

    @Override
    public void save(EsDrug esDrug) {
        this.esDrugRepository.save(esDrug);
    }

    @Override
    public void deleteById(Long id) {
        this.esDrugRepository.deleteById(id);
    }

    @Override
    public void update(EsDrug esDrug) {
        this.esDrugRepository.save(esDrug);
    }
}
